package com.mocchira.music.radio.web;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.BasicBSONObject;
import org.bson.types.BasicBSONList;

import com.mocchira.music.radio.FileUtil;
import com.mongodb.util.JSON;


/**
 * Servlet implementation class FMRHttpServlet
 */
@WebServlet("/music")
public class FMRHttpServlet extends HttpServlet {
    Log log = LogFactory.getLog(Class.class);
    protected static final long serialVersionUID = 1L;
    protected static final String OUTPUT_DIR_STR = "/usr/share/nginx/html/hots/";
    //protected static final String OUTPUT_DIR_STR = "C:/dev/work/";
    protected static final File OUTPUT_DIR = new File(OUTPUT_DIR_STR);
    
    protected static final String OUTPUT_TAG_DIR_STR = "/usr/share/nginx/html/tags/";
    //protected static final String OUTPUT_TAG_DIR_STR = "C:/dev/work/tags/";
    protected static final File OUTPUT_TAG_DIR = new File(OUTPUT_TAG_DIR_STR);
    
    protected static final String INDEX_FNAME = "idx.json";
    
    protected static final File OUTPUT_SELECTED_DIR_BASE = new File("/usr/share/nginx/html/selected/");
    //protected static final File OUTPUT_SELECTED_DIR_BASE = new File("C:/dev/work/selected/");
    protected static final File OUTPUT_SELECTED_INDEX = new File(OUTPUT_SELECTED_DIR_BASE, INDEX_FNAME);
    
    protected static final File OUTPUT_LATEST_DIR_BASE = new File("/usr/share/nginx/html/latest/");
    //protected static final File OUTPUT_LATEST_DIR_BASE = new File("C:/dev/work/latest/");
    protected static final File OUTPUT_LATEST_INDEX = new File(OUTPUT_LATEST_DIR_BASE, INDEX_FNAME);
    
    
    /**
     * @see HttpServlet#HttpServlet()
     */
    public FMRHttpServlet() {
        super();
    }
    
    protected void genSymLinkByTag(File src, String artist, List<Object> tags) throws Exception {
        for (Object tag: tags) {
            String encTag = URLEncoder.encode((String)tag, "UTF-8");
            File tagDir = new File(OUTPUT_TAG_DIR, (String)encTag);
            tagDir.mkdirs();
            File symlink = new File(tagDir, artist);
            String command = "ln -s " + src.getAbsolutePath() + " " + symlink.getAbsolutePath();
            Runtime.getRuntime().exec(command);
        }
    }
    
    protected void genArtistsIndex(File dir) throws Exception {
        File index = new File(dir, INDEX_FNAME);
        File[] files = dir.listFiles();
        BasicBSONList artists = new BasicBSONList();
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            if (file.getName().equals(INDEX_FNAME)) continue;
            artists.add(file.getName());
        }
        BasicBSONObject root = new BasicBSONObject();
        root.put("artists", artists);
        FileWriter writer = null;
        File tmp = null;
        try {
            tmp = File.createTempFile(dir.getName(), ".json");
            writer = new FileWriter(tmp);
            writer.write(root.toString());
        } finally {
            if (writer != null) writer.close();
        }
        tmp.renameTo(index);
    }
    
    protected void genIndex() throws Exception {
        File index = new File(OUTPUT_TAG_DIR, "idx.json");
        File[] dirs = OUTPUT_TAG_DIR.listFiles();
        BasicBSONList tags = new BasicBSONList();
        for (int i = 0; i < dirs.length; i++) {
            File dir = dirs[i];
            if (!dir.isDirectory()) continue;
            // artist index
            try {
                genArtistsIndex(dir);
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
                continue;
            }
            tags.add(dir.getName());
        }
        BasicBSONObject root = new BasicBSONObject();
        root.put("tags", tags);
        FileWriter writer = null;
        File tmp = null;
        try {
            tmp = File.createTempFile("tags", ".json");
            writer = new FileWriter(tmp);
            writer.write(root.toString());
        } finally {
            if (writer != null) writer.close();
        }
        tmp.renameTo(index);
    }
    
    protected List<Object> getSelectedTags() throws Exception {
        String json = FileUtil.getContents(OUTPUT_SELECTED_INDEX);
        BasicBSONObject obj = (BasicBSONObject)JSON.parse(json);
        BasicBSONList list = (BasicBSONList)obj.get("tags");
        return list;
    }
    
    protected void genSelectedIndex(String tag, List<Object> artists) throws Exception {
        File index = new File(OUTPUT_SELECTED_DIR_BASE, tag + ".json");
        FileWriter writer = null;
        File tmp = null;
        BasicBSONObject root = new BasicBSONObject();
        root.put("artists", artists);
        try {
            tmp = File.createTempFile("tags", ".json");
            writer = new FileWriter(tmp);
            writer.write(root.toString());
        } finally {
            if (writer != null) writer.close();
        }
        tmp.renameTo(index);
    }
    
    protected void genLatestIndex(Set<String> tags) throws Exception {
        /*
        BasicBSONList list = new BasicBSONList();
        for (String tag: tags) {
            list.add(tag);
        }
        */
        BasicBSONObject root = new BasicBSONObject();
        root.put("tags", tags);
        FileWriter writer = null;
        File tmp = null;
        try {
            tmp = File.createTempFile("tags", ".json");
            writer = new FileWriter(tmp);
            writer.write(root.toString());
        } finally {
            if (writer != null) writer.close();
        }
        tmp.renameTo(OUTPUT_LATEST_INDEX);
    }
    
    protected void genLatestTracks(String tag, List<Object> tracks) throws Exception {
        String encTag = URLEncoder.encode(tag, "UTF-8");
        File file = new File(OUTPUT_LATEST_DIR_BASE, encTag + ".json");
        FileWriter writer = null;
        File tmp = null;
        BasicBSONObject root = new BasicBSONObject();
        root.put("tracks", tracks);
        try {
            tmp = File.createTempFile("tracks", ".json");
            writer = new FileWriter(tmp);
            writer.write(root.toString());
        } finally {
            if (writer != null) writer.close();
        }
        tmp.renameTo(file);
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    IMusicResourceManager music = null;
	    request.setCharacterEncoding("UTF-8");
	    response.setCharacterEncoding("UTF-8");
	    try {

	        music = new MongoMusicResourceManager("127.0.0.1", 27017);
	        String m = request.getParameter("m");
	        if (m == null || m.length() == 0) throw new Exception("invalid parameter[m]");
	        if (m.equals("musics")) {
    	        String tag = request.getParameter("tag");
    	        if (tag == null || tag.length() > 100) throw new Exception("invalid parameter:[tag]");
    	        String start = request.getParameter("start");
    	        if (start == null || start.length() == 0) {
    	            music.writeJSONTrackList(tag, response.getWriter());
    	        } else {
    	            int s = Integer.parseInt(start);
    	            music.writeJSONTrackList(tag, response.getWriter(), s);
    	        }
	        } else if (m.equals("tags")) {
	            String topN = request.getParameter("n");
	            if (topN == null || topN.length() == 0) throw new Exception("invalid parameter[n]");
	            int n = Integer.parseInt(topN);
	            if (n > 50) throw new Exception("invalid parameter[n]:" + n);
	            music.writeTopNTagList(n, response.getWriter());
	        } else if (m.equals("hot")) {
	            music.writeJSONHotArtistList(response.getWriter());
	        } else if (m.equals("tracks")) {
	            String artist = new String(request.getParameter("a").getBytes("8859_1"), "UTF-8");
                if (artist == null || artist.length() > 100) throw new Exception("invalid parameter:[a]");
                music.writeJSONArtistTrackList(artist, response.getWriter());
	        } else if (m.equals("out_hot_tracks")) {
	            List<Object> list = music.getHotArtistList(300);
	            for (Object obj: list) {
	                String artist = (String)obj;
	                String fname = URLEncoder.encode(artist, "UTF-8");
	                FileWriter writer = null;
	                File tmp = null;
	                List<Object> tags = null;
	                try {
	                    tmp = File.createTempFile(fname, ".json");
	                    writer = new FileWriter(tmp);
	                    tags = music.writeJSONArtistTrackList(artist, writer);
	                } catch (Exception ex) {
	                    log.error(ex.getMessage(), ex);
	                    continue;
	                } finally {
	                    if (writer != null) writer.close();
	                }
	                File dst = new File(OUTPUT_DIR, fname);
                    tmp.renameTo(dst);
                    try {
                        genSymLinkByTag(dst, fname, tags);
                    } catch (Exception ex) {
                        log.error(ex.getMessage(), ex);
                        continue;
                    }
	            }
                genIndex();
	        } else if (m.equals("out_selected_tracks")) {
	            List<Object> tags = getSelectedTags();
	            for (Object tag: tags) {
	                String decTag = URLDecoder.decode((String)tag, "UTF-8");
	                List<Object> list = music.getArtistListByTag(decTag);
	                for (Object l: list) {
	                    String artist = (String)l;
	                    String fname = URLEncoder.encode(artist, "UTF-8");
	                    FileWriter writer = null;
	                    File tmp = null;
	                    try {
	                        tmp = File.createTempFile(fname, ".json");
	                        writer = new FileWriter(tmp);
	                        music.writeJSONArtistTrackList(artist, writer);
	                    } catch (Exception ex) {
	                        log.error(ex.getMessage(), ex);
	                        continue;
	                    } finally {
	                        if (writer != null) writer.close();
	                    }
	                    File dst = new File(OUTPUT_DIR, fname);
	                    tmp.renameTo(dst);
	                }
	                genSelectedIndex((String)tag, list);
	            }
	        } else if (m.equals("out_latest_tracks")) {
	            Map<String, List<Object>> tracksPerTags = music.getLatestTracks();
	            Set<String> keyset = tracksPerTags.keySet();
	            for (String tag: keyset) {
	                List<Object> tracks = tracksPerTags.get(tag);
	                genLatestTracks(tag, tracks);
	            }
	            genLatestIndex(keyset);
	        }

	    } catch (Exception ex) {
	        log.error(ex.getMessage(), ex);
	        response.sendError(400);
	    } finally {
	        if (music != null) music.close();
	    }
	}

}
